/*
	File:	video/Lighting.hpp
	Date:	2013-06-09
	Author:	Asteroth
*/

#ifndef __ZEN_LIGHTING_HPP__
#define __ZEN_LIGHTING_HPP__

#include "../gl.hpp"
#include "../math.hpp"

namespace zen {

	namespace video {


		class Lighting {

			public:

				/// Enable lighting.
				static inline void enable() {glEnable(GL_LIGHTING);}
				/// Enable a specific light.
				static inline void enable(unsigned int light) {glEnable(light);}
				/// Disable lighting.
				static inline void disable() {glDisable(GL_LIGHTING);}
				/// Disable a specific light.
				static inline void disable(unsigned int light) {glDisable(light);}

				/// The max number of lights.
				static inline GLint getMaxLightCount() {return maxLightCount;}
				/// The number of lights created.
				static inline GLint getLightCount() {return lightCount;}

				/// Creates a light and returns it's handle (0 on failure).
				static inline unsigned int create() {
					if (lightCount < maxLightCount) {
						for (int i = 0; i < maxLightCount; i++)
							if (lights[i]==false) {
								lights[i] = true;
								glEnable(GL_LIGHT0+i);
								return GL_LIGHT0+i;
							}
					}

					return 0;
				}

				/// Destroys a light.
				static inline void destroy(unsigned int light) {
					if (light>=GL_LIGHT0 && light<GL_LIGHT0+(unsigned int)maxLightCount) {
						glDisable(light);
						lights[light-GL_LIGHT0] = false;
					}
				}

				/// Set light settings.
				static inline void setPosition(unsigned int light, const glm::vec4 &pos) {
					glLightfv(light, GL_POSITION, &pos[0]);
				}

				static inline void setDiffuse(unsigned int light, const glm::vec4 &col) {
					glLightfv(light, GL_DIFFUSE, &col[0]);
				}

				static inline void setAmbient(unsigned int light, const glm::vec4 &col) {
					glLightfv(light, GL_AMBIENT, &col[0]);
				}

				static inline void setSpecular(unsigned int light, const glm::vec4 &col) {
					glLightfv(light, GL_SPECULAR, &col[0]);
				}

				static inline void setDirection(unsigned int light, const glm::vec4 &dir) {
					glLightfv(light, GL_SPOT_DIRECTION, &dir[0]);
				}

				static inline void setSpot(unsigned int light, float cutoff = 180.0f, float exponent = 0.0f) {
					glLightf(light, GL_SPOT_CUTOFF, cutoff);
					glLightf(light, GL_SPOT_EXPONENT, exponent);
				}

				static inline void setAttenuation(unsigned int light, float constant = 1.0f, float linear = 0.0f, float quadric = 0.0f) {
					glLightf(light, GL_CONSTANT_ATTENUATION, constant);
					glLightf(light, GL_LINEAR_ATTENUATION, linear);
					glLightf(light, GL_QUADRATIC_ATTENUATION, quadric);
				}

				static inline void setAmbientRadiation(const glm::vec4 &col) {
					glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &col[0]);
				}

				
			private:

				static GLint lightCount, maxLightCount;
				static bool* lights;

				static bool initialized;
				static bool initialize() {
					lightCount = 0;
					glGetIntegerv(GL_MAX_LIGHTS, &maxLightCount);
					lights = new bool[maxLightCount];
					for (GLint i = 0; i < maxLightCount; i++)
						lights[i] = false;
					glDisable(GL_LIGHT0);
					glDisable(GL_LIGHTING);
					glShadeModel(GL_SMOOTH);
					return true;
				}

		};
		

	} // namespace video

} // namespace zen

#endif
